/*
 * interface.c
 *
 *  Created on: 10/10/2011
 *      Author: OIM
 */

#include "interface.h"

#define MAX_BUFFER 535

void set_blockPerCluster(int32_t sectoresPerCluster){
	blockPerCluster = (sectoresPerCluster / secSize) / secPerBlock;
	blockPerCluster = 4;
}

int32_t conexionLibre()
{
	tipoSocket* ptrNuevo;
	int32_t hayConexion = 0;
	ptrNuevo = listaSockets;
	while( hayConexion == 0 )
	{
		if ( sem_trywait( &semSockets ) == 0 )
		{
			hayConexion = 1;
			pthread_mutex_lock( &mutexSockets );
		}
		else
			hayConexion = 0;
	}
	while ( ptrNuevo != NULL && ptrNuevo->libre != 1 )
		ptrNuevo = ptrNuevo->sgte;
	if ( ptrNuevo != NULL )
	{
		ptrNuevo->libre = 0;
		pthread_mutex_unlock ( &mutexSockets );
		return ptrNuevo->sock;
	}
	pthread_mutex_unlock ( &mutexSockets );
	return 0;
}

void liberarConexion( int32_t sock )
{
	tipoSocket* ptrNuevo;
	pthread_mutex_lock ( &mutexSockets );
	ptrNuevo = listaSockets;
	while ( ptrNuevo != NULL && ptrNuevo->sock != sock )
		ptrNuevo = ptrNuevo->sgte;
	if ( ptrNuevo != NULL )
	{
		ptrNuevo->libre = 1;
		sem_post( &semSockets );
	}
	pthread_mutex_unlock ( &mutexSockets );
	return;
}

void agregarConexion( sock ) /* al crear una conexion */
{
	tipoSocket* ptrNuevo = malloc ( sizeof( tipoSocket) );

	ptrNuevo->sock = sock;
	ptrNuevo->libre = 1;
	ptrNuevo->sgte = listaSockets;
	listaSockets = ptrNuevo;
}

unsigned char* Serializar(Paquete* unPaquete)
{
	unsigned char* retorno =malloc( 16 + 1 + 2 + 4 + (unPaquete->Length));
	memcpy(retorno,&unPaquete->ID,16);
	memcpy(retorno+16,&unPaquete->Sector,4);
    memcpy(retorno+16+4,&unPaquete->Tipo,1);
	memcpy(retorno+1+16+4,&unPaquete->Length,2);
	memcpy(retorno+1+16+2+4,unPaquete->Datos,unPaquete->Length);
	return retorno;
}

Paquete* DesSerializar(unsigned char *unStream)
{
	Paquete* unPaquete=malloc(sizeof(Paquete));
	memcpy(&unPaquete->ID,unStream,16);
	memcpy(&unPaquete->Sector,unStream+16,4);
    memcpy(&unPaquete->Tipo,unStream+16+4,1);
	memcpy(&unPaquete->Length,unStream+1+16+4,2);
	unPaquete->Datos=malloc(unPaquete->Length);
	memcpy(unPaquete->Datos,unStream+16+1+2+4,unPaquete->Length);
	return unPaquete;
}

int32_t conectar()
{
	int32_t sockfd;
	int32_t rc;
	int32_t i;
	char ID[16];
	Paquete* data = malloc ( sizeof(Paquete) );
	unsigned char* bufferEntrada = malloc ( 535 );
	unsigned char* bufferSalida;
	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
		perror("Error: No se pudo crear el socket return...");
		return -1;
	}
	struct sockaddr_in my_addr;
    my_addr.sin_family = AF_INET;    /* Ordenacion de bytes de la maquina*/
	my_addr.sin_port = htons(atoi( buscacfg("PORT") ) );  /* short, Ordenacion de bytes de la red*/
	my_addr.sin_addr.s_addr = inet_addr( buscacfg("IP") );
	memset(&(my_addr.sin_zero),'\0', 8);  /* poner a cero el resto de la estructura*/

    if (connect(sockfd, (struct sockaddr *)&my_addr,sizeof(my_addr))<0)
	{
		sockfd = -3;
		perror("\nError: No se pudo realizar el connect...");
		return sockfd;
	}
    escribir_logfile(NOMPS, 0, INFO, "Sending HANDSHAKE\n");
    genID(ID);
    for(i=0; i<16; i++)
    	data->ID[i] = ID[i];
    data->Tipo = HANDSHAKE_PPD;
    data->Length = 0;
    data->Sector = 0;
    data->Datos=malloc(1);
    data->Datos='\0';
    bufferSalida = Serializar(data);
    if ((send(sockfd,bufferSalida,24,0))<0)
    {
    	escribir_logfile(NOMPS, 0, ERROR, "Error en send()\n");
    	printf("send() error\n");
    	exit(127);
    }
    free( bufferSalida );
    rc = recv( sockfd, bufferEntrada, BUFFER_LENGTH, 0);
    if (rc < 0)
    {
    	escribir_logfile(NOMPS, 0, ERROR, "Error al recibir HANDSHAKE\n");
    	perror("Error al recibir Handshake\n");
    	exit(127);
    }
    else if (rc == 0)
    {
    	escribir_logfile(NOMPS, 0, ERROR, "Se cerro la conexion\n");
    	return 0;
    }
    escribir_logfile(NOMPS, 0, INFO, "Verifying HANDSHAKE\n");
    free( data->Datos );
    free( data );
    data = DesSerializar(bufferEntrada);
    if ( data->Tipo == HANDSHAKE_OK)
    	escribir_logfile(NOMPS, 0, INFO, "Connected to Store Device\n");
    else
    {
    	escribir_logfile(NOMPS, 0, ERROR, "Connection refused\n");
    	return 0;
    }
    free( bufferEntrada );
    free( data->Datos );
    free( data );
    return sockfd;
}

void genID(unsigned char dst[16])
{
   int32_t size = 16;
   static const unsigned char text[] = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
   int32_t i, len = (size);
   for ( i = 0; i < len; ++i)
      dst[i] = text[rand() % (sizeof text - 1)];
}

int32_t crearPoolConexiones(  int32_t maxConex )
{
	int32_t i;
	int32_t nuevoSocket;
	for( i=0 ; i< maxConex; i++ )
	{
		nuevoSocket = conectar();
		if( nuevoSocket > 0 )
			agregarConexion( nuevoSocket );
		else
			break;
	}
	if ( i == maxConex )
		return 1;
	else
		return 0;
}

tipoPedido* agregarPedido( unsigned char ID[16], int32_t bloque, int32_t sector, tipoPedido* listaPedidoLocal )
{
	tipoPedido* ptrNuevo = malloc ( sizeof( tipoPedido ) );
	tipoPedido* ptrLista = listaPedidoLocal;
	int32_t i;
	for( i=0 ; i<16; i++ )
		ptrNuevo->ID[i] = ID[i];
	ptrNuevo->bloque = bloque;
	ptrNuevo->sector = sector;
	ptrNuevo->sgte = NULL;
	if ( ptrLista == NULL )
		listaPedidoLocal = ptrNuevo;
	else
	{
		while ( ptrLista->sgte != NULL )
			ptrLista = ptrLista->sgte;
		ptrLista->sgte = ptrNuevo;
		return listaPedidoLocal;
	}
	return listaPedidoLocal;
}

int32_t putFATRegion(int32_t initSector, int32_t totalFatSize, unsigned char* data)
{
	int32_t sockPPD;
	sockPPD = conexionLibre();
	Paquete* paquete = (Paquete*)malloc(sizeof(Paquete));
	paquete->Datos=malloc(512);
	unsigned char* bufferSalida;
	int32_t i;
	int32_t j;
	int32_t k;
	int32_t bytesCopiados;
	for(bytesCopiados = 0 , k=0; k < totalFatSize/2; k++ )
	{
		for(i=0; i<2; i++,initSector++)
		{
			genID(paquete->ID);
			paquete->Length=512;
			paquete->Tipo=PUT_SECTOR;
			paquete->Sector=initSector;
			for( j=0 ; j < paquete->Length; bytesCopiados++, j++)
				paquete->Datos[j]= data[bytesCopiados];
			bufferSalida = Serializar(paquete);
			if ( send( sockPPD, bufferSalida, 535, 0 ) < 0 )
			{
				/* se colgo */
			}
			free( bufferSalida );
		}
	}
	free( paquete->Datos );
	free( paquete );
	liberarConexion( sockPPD );
	return 1;
}

int32_t sonDistintos( unsigned char ID[16], unsigned char otroID[16] )
{
	int32_t i;

	for( i=0; i<16; i++ )
	{
		if( ID[i] != otroID[i] )
			return 1;
	}
	return 0;
}

unsigned char* getFatRegion(int32_t reserveSize, int32_t fatSize )
{
	int32_t sockPPD;
	sockPPD = conexionLibre();
	tipoBloque bufferFAT[((reserveSize + fatSize)/2)];
	tipoPedido* listaLocaldePedidos = NULL;
	tipoPedido* ptrBusca;
	tipoPedido* ptrAnt;
	Paquete* data=(Paquete*)malloc(sizeof(Paquete));
	data->Datos = malloc(512);
	Paquete* paquete;
	unsigned char* bufferSalida;
	unsigned char* bufferEntrada = malloc ( 535 );
	int32_t posEnBloque;
	int32_t j,rc;
	int32_t bloque;
	int32_t sectoresEnviados;
	int32_t initSector = 0;

	for (sectoresEnviados = 0, bloque=0 ; bloque < ((reserveSize + fatSize)/2); bloque++ )
	{
		for( posEnBloque=0 ; posEnBloque<2;posEnBloque++,initSector++, sectoresEnviados++)
		{
			genID(data->ID);
			data->Length=512;
			data->Tipo=GET_SECTOR;
			data->Sector=initSector;
			for(j=0;j<data->Length;j++)
				data->Datos[j]='0';
			bufferSalida = Serializar(data);
			if ( send( sockPPD, bufferSalida, 535, 0 ) < 0 )
			{
				/* se colgo */
			}
			free(bufferSalida);
			listaLocaldePedidos = agregarPedido( data->ID, bloque, posEnBloque, listaLocaldePedidos);
			if ( sectoresEnviados == 256 || initSector == reserveSize+fatSize-1 )
			{
				while( listaLocaldePedidos != NULL )
				{
					rc = recv( sockPPD, bufferEntrada, 535, MSG_WAITALL);
					if ( rc < 0 )
					{
						printf("Error en recv pfs FAT\n");
						exit(127);
					}
					if ( rc == 0 )
					{
						printf("Se cerro la conexion FAT\n");
						exit(127);
					}
					paquete = DesSerializar(bufferEntrada);
					ptrBusca = listaLocaldePedidos;
					ptrAnt = NULL;
					while ( ptrBusca != NULL && sonDistintos(ptrBusca->ID,paquete->ID) )
					{
						ptrAnt = ptrBusca;
						ptrBusca = ptrBusca->sgte;
					}
					if( ptrBusca != NULL )
					{
						if( ptrAnt != NULL )
						{
							if( ptrBusca->sgte != NULL )
								ptrAnt->sgte = ptrBusca->sgte;
							else
								ptrAnt->sgte = NULL;
						}
						else
							listaLocaldePedidos = ptrBusca->sgte;
						for( j=0; j<512; j++)
							bufferFAT[ptrBusca->bloque][ptrBusca->sector][j] = paquete->Datos[j];
						free( ptrBusca );
					}
					free( paquete->Datos);
					free( paquete );
				}
				sectoresEnviados = 0;
			}
		}
	}
	free( bufferEntrada );
	free( data->Datos );
	free( data );
	liberarConexion( sockPPD );
	return bufferFAT;
}

unsigned char* getBootSector(int32_t clusterID, int32_t initSector )
{
	int32_t socketPD;
	socketPD = conexionLibre();
	tipoBloque bufferCluster[1];
	Paquete* data=(Paquete*)malloc(sizeof(Paquete));
	data->Datos=malloc(512);
	Paquete* paquete;
	unsigned char* bufferSalida;
	int32_t i;
	int32_t j,rc;
	int32_t nSector = 0;
	char* charSect = malloc(5);
	unsigned char ID[16];
	for(i=0 ;i<2;i++,initSector++, nSector++)
	{
		genID(ID);
		itoa(nSector,charSect);
		data->ID[15] = charSect[0];
		data->Length=512;
		data->Tipo=GET_SECTOR;
		data->Sector=initSector;
		for(j=0;j<data->Length;j++)
			data->Datos[j]='0';
		bufferSalida = Serializar(data);
		if ( send( socketPD, bufferSalida, 535, 0 ) < 0 )
		{
			/* se colgo */
		}
		free( bufferSalida );
	}
	unsigned char* bufferEntrada = malloc ( 535 );
	for(i=0; i<2; i++)
	{
		rc = recv( socketPD, bufferEntrada, 535, MSG_WAITALL);
		if ( rc < 0 )
		{

		}
		if ( rc == 0 )
		{

		}
		paquete = DesSerializar(bufferEntrada);
		if ( paquete->ID[15] == '0' )
		{
			for( j=0; j<512; j++)
				bufferCluster[0][0][j] = paquete->Datos[j];
		}
		else
		{
			for( j=0; j<512; j++)
				bufferCluster[0][1][j] = paquete->Datos[j];
		}
		free( paquete->Datos );
		free( paquete );
	}
	free( data->Datos );
	free( data );
	free( charSect );
	free( bufferEntrada );
	liberarConexion(socketPD);
	return bufferCluster;
}

unsigned char* getCluster( int32_t clusterID, int32_t initSector )
{
	int32_t socketPD;
	socketPD = conexionLibre();
	tipoBloque bufferCluster[4]; /* MAXIIII CAMBIAR ACA EL 4, por bufferSize/512/2  osea la cantidad de bloques! */
	Paquete* data=(Paquete*)malloc(sizeof(Paquete));
	data->Datos=malloc(512);
	Paquete* paquete;
	tipoPedido* listaLocaldePedidos = NULL;
	unsigned char* bufferSalida;
	unsigned char* bufferEntrada = malloc ( 535 );
	tipoPedido* ptrBusca;
	tipoPedido* ptrAnt;
	int32_t j,rc;
	int32_t bloque;
	int32_t posEnBloque;
	int32_t sectoresEnviadosTotales;
	int32_t sectoresEnviados;

	for (sectoresEnviados = 0, sectoresEnviadosTotales = 1, bloque=0 ; bloque < 4/* ( ( bufferSize/512 )/2 ) */; bloque++ ) /* MAXIIIIIIIII */
	{																				/* CUANDO TENGAS PARA PASAR EL BUFFERSIZE, CREO QUE ES ASI LA CUENTA CHEQUEALO PARA QUE DE ACA EN BLOQUES */
		for( posEnBloque=0 ; posEnBloque<2; posEnBloque++,initSector++, sectoresEnviados++, sectoresEnviadosTotales++ )
		{
			genID(data->ID);
			data->Length=512;
			data->Tipo=GET_SECTOR;
			data->Sector=initSector;
			for(j=0;j<data->Length;j++)
				data->Datos[j]='0';
			bufferSalida = Serializar(data);
			if ( send( socketPD, bufferSalida, 535, 0 ) < 0 )
			{
				/* se colgo */
			}
			free(bufferSalida);
			listaLocaldePedidos = agregarPedido( data->ID, bloque, posEnBloque, listaLocaldePedidos);
			if ( sectoresEnviados == 16 || sectoresEnviadosTotales == 8 /* sectoresEnviadosTotales == bufferSize/512 */ ) /* ACA EN SECTORES */
			{
				while( listaLocaldePedidos != NULL )
				{
					rc = recv( socketPD, bufferEntrada, 535, MSG_WAITALL);
					if ( rc < 0 )
					{
						printf("Error en recv pfs FAT\n");
						exit(127);
					}
					if ( rc == 0 )
					{
						printf("Se cerro la conexion FAT\n");
						exit(127);
					}
					paquete = DesSerializar(bufferEntrada);
					ptrBusca = listaLocaldePedidos;
					ptrAnt = NULL;
					while ( ptrBusca != NULL && sonDistintos(ptrBusca->ID,paquete->ID) )
					{
						ptrAnt = ptrBusca;
						ptrBusca = ptrBusca->sgte;
					}
					if( ptrBusca != NULL )
					{
						if( ptrAnt != NULL )
						{
							if( ptrBusca->sgte != NULL )
								ptrAnt->sgte = ptrBusca->sgte;
							else
								ptrAnt->sgte = NULL;
						}
						else
							listaLocaldePedidos = ptrBusca->sgte;
						for( j=0; j<512; j++)
							bufferCluster[ptrBusca->bloque][ptrBusca->sector][j] = paquete->Datos[j];
						free( ptrBusca );
					}
					free( paquete->Datos);
					free( paquete );
				}
				sectoresEnviados = 0;
			}
		}
	}
	free( data->Datos );
	free( data );
	free( bufferEntrada );
	liberarConexion( socketPD );
	return bufferCluster;
}

int32_t putCluster(int32_t clusterID, int32_t initSector, unsigned char* data)
{
	int32_t sockPPD;
	sockPPD = conexionLibre();
	Paquete* paquete = (Paquete*)malloc(sizeof(Paquete));
	paquete->Datos=malloc(512);
	unsigned char* bufferSalida;
	int32_t i;
	int32_t j;
	int32_t k;
	int32_t bytesCopiados;
	for(bytesCopiados = 0 , k=0; k < blockPerCluster; k++ )
	{
		for(i=0; i<2; i++,initSector++)
		{
			genID(paquete->ID);
			paquete->Length=512;
			paquete->Tipo=PUT_SECTOR;
			paquete->Sector=initSector;
			for( j=0 ; j < paquete->Length; bytesCopiados++, j++)
				paquete->Datos[j]= data[bytesCopiados];
			bufferSalida = Serializar(paquete);
			if ( send( sockPPD, bufferSalida, 535, 0 ) < 0 )
			{
				/* se colgo */
			}
			free( bufferSalida );
		}
	}
	free( paquete->Datos );
	free( paquete );
	liberarConexion( sockPPD );
	return 1;
}
